import argparse
import json
import os
import re
import shutil
import subprocess
import sys
import time
from typing import Tuple, List
from logger import logger


base_path = os.path.dirname(os.path.realpath(__file__))


def install_dependencies():
    requirements_path = os.path.join(base_path, 'requirements.txt')
    if sys.platform == 'win32':
        command = 'pip install -r'
    else:
        command = 'python3 -m pip install -r'
    logger.info('安装必要的依赖...')
    subprocess.run(f'{command} {requirements_path}', check=True)
    logger.info('依赖安装完毕')


def get_path() -> Tuple[str, str]:
    """ 获取命令行参数 """
    parser = argparse.ArgumentParser(description='处理命令行参数')
    parser.add_argument('-p', '--path', help='文件路径', required=True)
    parser.add_argument('-s', '--serial', help='安卓设备序列号', required=False)
    args = parser.parse_args()
    logger.info(f"传入的路径是: {args.path}")
    if args.serial:
        logger.info(f"传入的安卓设备序列号是: {args.serial}")
    else:
        logger.info("未提供安卓设备序列号")
    return args.path, args.serial


def app_folder_list(folder_path) -> Tuple[List[str], str, str]:
    """
    获取各个app文件夹或某个app下的air文件
    :param folder_path: 传入来的命令行路径
    :return: 获取到的app路径或.air路径
    """
    folder_list = []
    if not os.path.exists(folder_path):
        logger.error("提供的路径不存在")
        return folder_list, '', ''

    # 如果传入的目录下全是air脚本，则为运行单个app截图
    all_air = True
    for entry in os.listdir(folder_path):
        full_path = os.path.join(folder_path, entry)
        if os.path.isdir(full_path) and not full_path.endswith('-screenshot'):
            folder_list.append(full_path)
            if not entry.endswith('.air'):
                all_air = False  # 如果发现不是以.air结尾的文件夹，更改标志

    if all_air and folder_list:
        return folder_list, 'app', folder_path
    else:
        return folder_list, 'apps', ''


def stop_app(device, package_name):
    # 停止应用
    if device is None:
        subprocess.run(f'adb shell am force-stop {package_name}')
    else:
        subprocess.run(f'adb -s {device} shell am force-stop {package_name}')
    time.sleep(2.0)


def modify_file(content, file_py_path):
    """修改脚本内容"""
    # 插入等待代码
    modified_content = re.sub(r"(\.(click\(\)|swipe\(.*?\)))", r'.wait(10)\1', content)
    # 重新写入文件
    with open(file_py_path, 'w', encoding='utf-8') as f:
        f.write(modified_content)


def screenshot(device, screenshot_file_path):
    """
    截图
    :param device: 设备序列号
    :param screenshot_file_path: 截图存放路径
    :return:
    """
    if device is None:
        subprocess.run('adb shell screencap -p /sdcard/screenshot.png', shell=True)
        subprocess.run(f'adb pull /sdcard/screenshot.png {screenshot_file_path}', shell=True)
    else:
        subprocess.run(f'adb -s {device} shell screencap -p /sdcard/screenshot.png', shell=True)
        subprocess.run(f'adb -s {device} pull /sdcard/screenshot.png {screenshot_file_path}', shell=True)


def recover_file(file_py_path, original_content):
    """删除追加的内容，恢复原内容"""
    with open(file_py_path, 'w', encoding='utf-8') as f:
        f.write(original_content)


def process_air_file(file_path, image_path, times, package_name, device):
    """
    执行单个.air脚本
    :param file_path: .air脚本的完整路径
    :param image_path: 存放截图的文件夹路径
    :param times: 重试次数
    :param package_name: 应用包名
    :param device: 设备序列号
    :return:
    """
    logger.info(f'开始运行文件：{file_path}')
    # 提取.air文件夹名字
    file_name = re.search(r'\\([^\\]+)\.air', file_path).group(1)
    # 截图存放路径
    screenshot_file_path = image_path + '\\' + file_name + '.png'
    logger.info(f'截图存放路径：{screenshot_file_path}')
    # .air文件夹下的py文件
    file_py_path = os.path.join(file_path, file_name + '.py')

    # 保存原始.air文件夹下的py文件内容
    with open(file_py_path, 'r', encoding='utf-8') as f:
        original_content = f.read()
        content = original_content

    # 判断截图是否要人工进行
    if "人工截图" in original_content:
        logger.warning(f'{file_path} 此截图需要人工进行')
        # 需人工截图，用提示图片代替界面截图
        shutil.copyfile(f'{base_path}/img/artificial.png', screenshot_file_path)
    else:
        modify_file(content, file_py_path)
        if device is None:
            runCommand = ["airtest", "run", file_path]
        else:
            runCommand = ["airtest", "run", file_path, "--device", "Android://127.0.0.1:5037/" + device]
        logger.debug(f'运行.air脚本：{runCommand}')
        try:
            result = subprocess.run(runCommand, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
            # 记录airtest日志输出
            logger.debug(f"Airtest 输出：{result.stdout}\n{result.stderr}")
            screenshot(device, screenshot_file_path)
        except subprocess.CalledProcessError as e:
            logger.error(f".air脚本执行失败，退出代码：{e.returncode}, 错误信息：{e.stderr}")
            if times < 3:
                times += 1
                logger.error(f'{file_path} 脚本运行报错,第{times}次重试')
                recover_file(file_py_path, original_content)
                stop_app(device, package_name)
                process_air_file(file_path, image_path, times, package_name, device)
                return
            else:
                logger.error(f'{file_path} 脚本运行报错,重试次数已达到3次')
                shutil.copyfile(f'{base_path}/img/error.png', screenshot_file_path)

        recover_file(file_py_path, original_content)
        stop_app(device, package_name)


def run_air_file(file_list, flags, folder_path, device):
    """

    :param file_list: app文件夹路径或.air文件夹路径
    :param flags: 单个app或多个app
    :param folder_path: 命令行传入的参数path(app)
    :param device: 设备序列号
    :return:
    """
    if not file_list:
        sys.exit(1)
    if flags == 'app':
        app_image_path = folder_path + '-screenshot' + '-' + time.strftime('%y%m%d%H%M%S')
        logger.info(f'创建存放截图的文件夹：{app_image_path}')
        os.makedirs(app_image_path)
        air_files = natsorted(file_list, alg=ns.PATH)
        pretty_printed_list = json.dumps(air_files, indent=2)
        logger.debug(f'排序后的.air文件：{pretty_printed_list}')
        package_name = re.search(r'\\([^\\]+)\\[^\\]+\.air$', air_files[0]).group(1)
        logger.info(f'当前应用程序包名：{package_name}')
        for air_file in air_files:
            process_air_file(air_file, app_image_path, 0, package_name, device)
    else:
        # 去掉存放截图的文件夹
        app_list = [file for file in file_list if not re.search(r'-screenshot-\d+', file)]
        logger.info(f'获取到的app文件夹：{app_list}')
        for app_path in app_list:
            app_image_path = app_path + '-screenshot' + '-' + time.strftime('%y%m%d%H%M%S')
            logger.info(f'创建存放截图的文件夹：{app_image_path}')
            os.makedirs(app_image_path)
            air_files = natsorted([os.path.join(app_path, f) for f in os.listdir(app_path) if f.endswith(".air")], alg=ns.PATH)
            pretty_printed_list = json.dumps(air_files, indent=2)
            logger.debug(f'{app_path}排序后的.air文件：{pretty_printed_list}')
            package_name = re.search(r'\\([^\\]+)\\[^\\]+\.air$', air_files[0]).group(1)
            logger.info(f'当前应用程序包名：{package_name}')
            for air_file in air_files:
                process_air_file(air_file, app_image_path, 0, package_name, device)


if __name__ == "__main__":
    install_dependencies()
    from natsort import natsorted, ns
    path, device = get_path()
    app_path_list, flag, param_path = app_folder_list(path)
    run_air_file(app_path_list, flag, param_path, device)


